package cn.edu.sjtu.intent;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import cn.edu.sjtu.DedexerPlus;
import cn.edu.sjtu.permission.PermissionChecker;

public class IntentChecker {

	private HashSet<IntentPair> rIntentSet;
	private HashSet<IntentPair> sIntentSet;
	
	class IntentPair {
		private String action;
		private String permission;
		private String uri;
		private String flag;
		private String extra;
		
		IntentPair(String a, String p) {
			action = a;
			permission = p;
			uri = null;
			flag = null;
			extra = null;
		}
		
		IntentPair(String a, String p, String u, String f, String e) {
			action = a;
			permission = p;
			uri = u;
			flag = f;
			extra = e;
		}
	}
	
	public IntentChecker() {
		rIntentSet = new HashSet<IntentPair>();
		sIntentSet = new HashSet<IntentPair>();
	}
	
	public void checkSendPermission(DedexerPlus dp) {
		for (IntentPair ip : sIntentSet) {
			if (ip.permission == null) {
				// Warning
			}
			if (ip.extra != null) {
				// Warning
			}
		}
	}
	
	public void addIntentPair(String action, String permission) {
		rIntentSet.add(new IntentPair(action, permission));
		System.out.println("###" + action + " " + permission + "###");
	}
	
	public void addIntentPair(String action, String permission, String uri, String flag, String extra) {
		sIntentSet.add(new IntentPair(action, permission, uri, flag, extra));
		System.out.println("###" + action + " " + permission + " " + uri + " " + flag + " " + extra + "###");
	}
	
	public void addIntentPair(String methodName, long filePos, String[] para, String flag) {
		if (flag.equals("receive")) {
			getRegValue(methodName, filePos, para, "receive");
		} else if (flag.equals("send")) {
			getRegValue(methodName, filePos, para, "send");
		}
	}
	
	public void anaylysisXML(String path) {
		DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder dombuilder = domfac.newDocumentBuilder();
			InputStream is = new FileInputStream(path);
			Document doc = dombuilder.parse(is);
			
			Node app = doc.getElementsByTagName("application").item(0);
			for (Node act = app.getFirstChild(); act != null; act = act.getNextSibling()) { //activity, cp ...
				for (Node intF = act.getFirstChild(); intF != null; intF = intF.getNextSibling()) {
					if (intF.getNodeName().equals("intent-filter")) {
						for (Node intent = intF.getFirstChild(); intent!= null; intent = intent.getNextSibling()) {
							if(intent.getNodeName().equals("action")){
								String a = intent.getAttributes().getNamedItem("android:name").getNodeValue();
								rIntentSet.add(new IntentPair(a, null));
							}
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void getRegValue(String methodName, long filePos, String[] para, String func) {
		List<HashMap<String, String>> paramList = null;
		HashMap<Long, List<HashMap<String, String>>> ll = DedexerPlus.registerMapsForClasses.get(methodName);
		if (ll != null) {
			paramList = ll.get(new Long(filePos));
			if (paramList != null) {
				for (HashMap<String, String> is : paramList) {
					String[] pas = new String[para.length];
					for (int i = 0; i < para.length; i++) {
						String reg = para[i];
						String rv = is.get(String.valueOf(reg));
						if (rv != null) {
							if (rv.startsWith("VALUE(")) { // other class's field
								String field = rv.substring(6, rv.length() - 1);
								String oclassName = field.substring(0, field.lastIndexOf("."));
								HashMap<Long, List<HashMap<String, String>>> ohm = DedexerPlus.registerMapsForClasses.get(oclassName + ".<clinit>");
								if (ohm != null && !ohm.equals(ll)) { // avoid endless loop
									Iterator it = ohm.entrySet().iterator();
									while (it.hasNext()) {
										Map.Entry e1 = (Entry) it.next();
										List<HashMap<String, String>> regMapList = (List) e1.getValue();
										for (HashMap<String, String> rm : regMapList) {
											String fv = rm.get(field);
											if (fv != null && !fv.equals("")) {
												// fv
												if (pas[i] == null)	
													pas[i] = fv + "|";
												else
													pas[i] = pas[i] + fv + "|";
											}
										}
									}
								}
							} else {
								// rv
								pas[i] = rv;
							}
						}
					}
					if (func.equals("receive")) {
						String action = pas[0], permission = null;
						String[] as = action.split("[|]");
						for (String a : as) {
							a = a.substring(a.indexOf("(") + 1, a.indexOf(")"));
							a = a.substring(1, a.length() - 1);
							if (pas.length > 1) {
								permission = pas[1];
								
								String[] ps = permission.split("[|]");
								for (String p : ps) {
									addIntentPair(a, p);
								}
							} else {
								addIntentPair(a, null);
							}
						}
					} else if (func.equals("send")) {
						String action = pas[0], permission = null;
						String[] as = action.split("[|]");
						for (String a : as) {
							String ac = null, ur = null, fl = null, ex = null;
							if (a.contains("Intent(")) {
								int i = a.indexOf("ACTION:");
								ac = a.substring(i + 7, a.indexOf(";", i));
								
								i = a.indexOf("Uri:");
								ur = a.substring(i + 4, a.indexOf(";", i));
								
								i = a.indexOf("FLAG:");
								fl = a.substring(i + 5, a.indexOf(";", i));
								
								i = a.indexOf("EXTRA:");
								ex = a.substring(i + 6, a.indexOf(";", i));
							} else {
								ac = a;
							}
							if (pas.length > 1) {
								permission = pas[1];
								
								String[] ps = permission.split("[|]");
								for (String p : ps) {
									addIntentPair(ac, p, ur, fl, ex);
								}
							} else {
								addIntentPair(ac, null, ur, fl, ex);
							}
						}
					}
				}
			}
		}
	}
	
	public static void main(String[] args) {
		IntentChecker ic = new IntentChecker();
		ic.anaylysisXML("D:\\Temp\\AngryBirds_2.0.2\\AndroidManifest.xml");
	}
}
